Skip to content

Conversation

@marovole
Copy link

@marovole marovole commented Jan 8, 2026

Summary

Fix critical code injection vulnerability in calculator.ts by replacing unsafe eval() with a secure recursive descent math parser.

🔴 Vulnerability (Critical)

File: examples/next-js-chatbot-starter-template/lib/tools/calculator.ts

Using eval() with user-provided expressions allows arbitrary JavaScript code execution. An attacker could execute malicious code through the calculator tool.

Example Attack Vector

// If expression contains: "1; require('child_process').execSync('rm -rf /')"
// eval() will execute this as JavaScript code!
const result = eval(expression);  // DANGEROUS!

✅ Fix

Replaced eval() with a complete secure math expression parser:

  1. tokenize() - Lexical analysis to extract numbers, operators, and parentheses
  2. parseExpression() - Recursive descent parser with proper operator precedence
  3. Whitelist approach - Only allows numeric values and mathematical operators

Before

execute: async ({ expression }) => {
  const result = eval(expression);  // VULNERABLE
  return { result: String(result) };
}

After

// Tokenizer
function tokenize(expr: string): Token[] {
  const tokens: Token[] = [];
  let i = 0;
  while (i < expr.length) {
    // Handle numbers, operators, parentheses
    // Reject anything else
  }
  return tokens;
}

// Recursive descent parser
function parseExpression(tokens: Token[]): number {
  // Handles +, -, *, /, ** with proper precedence
  // Only processes validated tokens
}

execute: async ({ expression }) => {
  const tokens = tokenize(expression);
  const result = parseExpression(tokens);  // SAFE
  return { result: String(result) };
}

Supported Operations

Operation Example Result
Addition 2 + 3 5
Subtraction 10 - 4 6
Multiplication 3 * 4 12
Division 20 / 5 4
Exponentiation 2 ** 10 1024
Parentheses (2 + 3) * 4 20
Precedence 2 + 3 * 4 14

Testing

  • Basic arithmetic operations work correctly
  • Operator precedence is respected
  • Parentheses grouping works
  • Malicious JavaScript code is rejected
  • Invalid characters cause parsing errors

References


Summary by cubic

Replaced unsafe eval() in the calculator tool with a safe math expression parser to prevent code injection. Supports +, -, *, /, **, and parentheses with correct precedence.

  • Bug Fixes
    • Removed eval(); added tokenizer and recursive descent parser.
    • Whitelists numbers and math operators; rejects invalid characters.
    • Returns clear error messages from execute() instead of a generic failure.

Written for commit 3f20266. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Added support for exponentiation operator (**) in mathematical expressions.
  • Bug Fixes

    • Improved error handling with clearer error messages for invalid calculations.
    • Enhanced calculator robustness and operational reliability.

✏️ Tip: You can customize this high-level summary in your review settings.

…vent code injection

## Summary
Fix critical code injection vulnerability in calculator.ts by replacing
unsafe eval() with a secure recursive descent math parser.

## Vulnerability
Using eval() with user-provided expressions allows arbitrary JavaScript
code execution. An attacker could execute malicious code through the
calculator tool.

## Fix
- Remove eval() completely
- Implement tokenize() function for lexical analysis
- Implement parseExpression() recursive descent parser
- Support +, -, *, /, ** operators with proper precedence
- Support parentheses for grouping
- Only allow numeric values and mathematical operations

## Testing
- Verified basic arithmetic: 2+2, 10-5, 3*4, 20/4
- Verified operator precedence: 2+3*4 = 14
- Verified exponentiation: 2**10 = 1024
- Verified parentheses: (2+3)*4 = 20
- Verified malicious input is rejected
@changeset-bot
Copy link

changeset-bot bot commented Jan 8, 2026

⚠️ No Changeset found

Latest commit: 3f20266

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

📝 Walkthrough

Walkthrough

The calculator tool was refactored to replace eval-based calculations with a safe tokenizer and recursive-descent parser supporting operator precedence, exponentiation, and unary operators. The public API remains unchanged while security is substantially improved through elimination of eval.

Changes

Cohort / File(s) Summary
Calculator Tool Refactoring
examples/next-js-chatbot-starter-template/lib/tools/calculator.ts
Replaced eval-based computation with a full expression tokenizer and recursive-descent parser. Implemented operator precedence (addition/subtraction, multiplication/division, exponentiation) and unary operators. Added safeEvaluate() function with robust error handling for invalid tokens and malformed expressions. Enhanced error propagation with specific error messages. No changes to exported calculatorTool signature.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A parser rose where eval once dwelled,
With tokens dancing, precedence well-quelled,
No dangers lurk in expressions now,
Just safe recursion and structured flow,
✨ Math made secure, the safer way!

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main security fix: replacing eval() with a safe parser to prevent code injection, which matches the primary change in the changeset.
Description check ✅ Passed The description is comprehensive and follows the template structure with all key sections: vulnerability details, fix explanation, supported operations, testing checklist, and references. It provides clear before/after code examples and security context.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
examples/next-js-chatbot-starter-template/lib/tools/calculator.ts (1)

18-25: Consider validating number format to catch malformed decimals.

The current implementation allows numbers like 1.2.3 to be silently parsed as 1.2 due to parseFloat behavior. While not a security issue, this could confuse users. Consider adding validation for multiple decimal points.

♻️ Optional improvement for stricter number validation
     if (/\d/.test(char) || (char === "." && i + 1 < chars.length && /\d/.test(chars[i + 1]))) {
       let num = "";
+      let hasDecimal = false;
       while (i < chars.length && (/\d/.test(chars[i]) || chars[i] === ".")) {
+        if (chars[i] === ".") {
+          if (hasDecimal) throw new Error("Invalid number format: multiple decimal points");
+          hasDecimal = true;
+        }
         num += chars[i++];
       }
       tokens.push({ type: "number", value: parseFloat(num) });
       continue;
     }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e0c3b7 and 3f20266.

📒 Files selected for processing (1)
  • examples/next-js-chatbot-starter-template/lib/tools/calculator.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.ts: Maintain type safety in TypeScript-first codebase
Never use JSON.stringify; use the safeStringify function instead, imported from @voltagent/internal

Files:

  • examples/next-js-chatbot-starter-template/lib/tools/calculator.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (5)
examples/next-js-chatbot-starter-template/lib/tools/calculator.ts (5)

4-8: LGTM!

The type definitions are clear and appropriate for the internal tokenizer/parser implementation.


10-47: LGTM - Secure tokenizer with whitelist approach.

The tokenizer correctly implements a whitelist approach, only allowing valid mathematical characters. This effectively prevents code injection by rejecting any unexpected characters.

One minor observation: numbers like 1.2.3 will be parsed as 1.2 due to parseFloat behavior (silently ignoring invalid trailing content), which could be confusing for users but isn't a security concern.


49-118: LGTM - Well-structured recursive-descent parser.

The parser correctly implements:

  • Standard operator precedence (+/- < */÷ < ** < unary)
  • Right-associativity for exponentiation (2**3**4 = 2**(3**4))
  • Proper parentheses handling with error detection for mismatched parens
  • Unary operator support

Division by zero returns Infinity/-Infinity per JavaScript/IEEE 754 semantics, which is acceptable behavior.


120-124: LGTM!

Clean orchestration of the tokenize-parse pipeline with proper empty expression handling.


135-150: LGTM - Secure integration of the safe evaluator.

The execute function now correctly uses safeEvaluate instead of eval, eliminating the code injection vulnerability. Error handling is improved by propagating specific error messages to help users understand what went wrong.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant